<?php
/**
 * This file is part of Swoft.
 *
 * @link     https://swoft.org
 * @document https://swoft.org/docs
 * @contact  group@swoft.org
 * @license  https://github.com/swoft-cloud/swoft/blob/master/LICENSE
 */

use App\Lib\RpcClient\RpcResult;
use App\Lib\RpcRequest\RpcRequest;
use Swoft\Db\Exception\DbException;
use Swoft\Http\Message\Request;
use App\Lib\Migrate\Migrate;
use Swoft\Bean\BeanFactory;
use App\Lib\RpcClient\RpcClient;

include_once(__DIR__ . '/Client.php'); // 加载 Rpc Client 方法

/**
 * 获取 client ip地址
 * @return array|mixed|string
 */
function ip(){
    $req= Swoft\Context\Context::get()->getRequest();
    if($req->server('http_x_forwarded_for')){
        return $req->server('http_x_forwarded_for');
    }elseif($req->server('http_client_ip')){
        return $req->server('http_client_ip');
    }else{
        return $req->server('remote_addr');
    }
}

/**
 * 生成唯一ID uuid
 * @return string
 */
function uuid() {
    if (function_exists ( 'com_create_guid' )) {
        return com_create_guid ();
    } else {
        mt_srand ( ( double ) microtime () * 10000 ); //optional for php 4.2.0 and up.随便数播种，4.2.0以后不需要了。
        $charid = strtoupper ( md5 ( uniqid ( rand (), true ) ) ); //根据当前时间（微秒计）生成唯一id.
        $hyphen = chr ( 45 ); // "-"
        $uuid = '' . //chr(123)// "{"
            substr ( $charid, 0, 8 ) . $hyphen . substr ( $charid, 8, 4 ) . $hyphen . substr ( $charid, 12, 4 ) . $hyphen . substr ( $charid, 16, 4 ) . $hyphen . substr ( $charid, 20, 12 );
        //.chr(125);// "}"
        return $uuid;
    }
}

/**
 * 获取本地IP地址
 * @return mixed
 */
function getLocalIP(){
    $ip = swoole_get_local_ip();
    return current($ip);
}

/**
 * 获取用户自定义配置
 * 自动拼接了 tenant 用来统一配置获取方式
 * 注意：本方法只可以在 RPC 被调用的时候使用
 * @param $key
 * @param $default
 * @return mixed
 */
function userConfig ($key, $default) {
    $tenant = strtolower(getTenant());
    $configKey = trim("$tenant.$key");
    return config($configKey, $default);
}

/**
 * 从http url 中获取Tenant
 * url 格式 http://url:port/tenant..
 * @return string
 */
function getTenant () {
//    [$status, $path, $route] = Context()->getRequest()->getAttribute(Request::ROUTER_ATTRIBUTE);
    [$status, $path] = Context()->getRequest()->getAttribute(Request::ROUTER_ATTRIBUTE);
    preg_match_all('/\/?([a-zA-Z0-9]+)*/', $path, $match);
    if (!isset($match[1][0]) || empty($match[1][0])) {
        return '';
    }
    return ucfirst($match[1][0]);
}

/**
 * 回调地址获取service
 * url http://url:port/tenant/common_permission_permission_action/notify
 * @return string
 */
function getService(){
    //jiujiu/common_permission_permission_notify/notify
    [$status, $path] = Context()->getRequest()->getAttribute(Request::ROUTER_ATTRIBUTE);
    $service = array_values(array_filter(explode("/", $path)));
    if(!isset($service[1]) && empty($service[1])){
        return '';
    }
    //接下来进行服务匹配
    $preg = preg_match('/^([a-zA-Z0-9]+)_([a-zA-Z0-9]+)_([a-zA-Z0-9]+)_([a-zA-Z0-9]+)$/', $service[1]);

    if (!$preg) {
        return '';
    }

    $data = explode("_", $service[1]);

    return ucfirst($data[0]).'.'.ucfirst($data[1]).'.'.ucfirst($data[2]).'.'.ucfirst($data[3]);
}

/**
 * 使用携程的方式删除Redis Key
 * @param $key
 */
function sgoDeleteRedisKey ($key) {
    sgo(
        function () use($key) {
            \Swoft\Redis\Redis::del($key);
        }
    );
}

/**
 * @param string $method
 * @param array $option
 * @return string
 */
function mMigrate($method = 'up', $option = []){
    $migrateHelper = \Swoft\Bean\BeanFactory::getBean(Migrate::class);
    return $migrateHelper->{$method}($option);
}

/**
 * @return string $salt
 */
function create_salt(): string
{
    $chars = md5(uniqid(mt_rand(), true));
    return substr ( $chars, 0, 6 );
}

/**
 * @param $password
 * @param $salt
 * @return string
 */
function create_password($password, $salt): string
{
    return md5(md5($password.$salt).$salt);
}
/**
 * 通过uuid获取唯一外键id,依赖于uuid
 * @param $uuid
 * @param string $salt
 * @return string
 */
function create_item_id($uuid, $salt = '123456'): string
{
    return md5($salt.$uuid);
}

/**
 * @param int $error_code
 * @param string $message
 * @param array $result
 * @return array
 */
function serviceReturn(int $error_code, string $message, array $result = []):array
{
    $retData = [];
    $retData['error_code']    = $error_code;
    $message? $retData['message'] = $message:'';
    $result? $retData['result'] = $result:[];
    return $retData;
}

/**
 * @param string $baseUri
 * @param string $uri
 * @param string $method
 * @param array $data
 * @param array $headers
 * @param bool $flag
 * @return string
 */
function curl(string $baseUri, string $uri, string $method = 'GET', $data = [], array $headers = [], bool $flag = false){
    $client = new \GuzzleHttp\Client(['base_uri' => $baseUri, 'headers' => $headers]);
    if($method == 'POST'){
        if(!$flag){
            $filed = 'form_params';
        }else{
            $filed = 'json';
        }
        $response = $client->request($method, $uri, ['verify' => false, $filed => $data]);
    }else{
        $response = $client->request($method, $uri, ['verify' => false, 'query' => $data]);
    }
    return $response->getBody()->getContents();
}

/**
 * @param string $data
 * @param string $salt
 * @return string
 */
function encode_exchange(string $data, $salt = 'F6DeTa')
{
    $str = (string)time();
    $str .= '_'.(string)$data;
    return base64_encode($salt.base64_encode($str));
}

/**
 * @param string $data
 * @param string $salt
 * @return mixed|string
 */
function decode_exchange(string $data, $salt = 'F6DeTa')
{
    $str = base64_decode($data);
    $str = str_replace($salt, '', $str);
    //获取手机号 获取到了解密信息
    $str = base64_decode($str);
    $arr = explode('_', $str);
    if(isset($arr[1]) && !empty($arr[1])){
        return $arr[1];
    }else{
        return '';
    }
}

/**
 * 判断租户是否合法
 * 存在不存在 是不是可用状态
 * @param $tenant
 * @return bool
 * @throws DbException
 */
function tenant_check($tenant)
{
    $db = env('APP_ENV')."_gateway_admin";
    $query = \Swoft\Db\DB::table('tenant')->db($db)->where(['prefix' => $tenant, 'frozen_state' => 0])->first();
    if(!empty($query)){
        return true;
    }
    return false;
}

//create_database
/**
 * 创建数据库
 * @param $name
 * @return bool
 */
function create_database($name){
    return \Swoft\Db\DB::db('mysql')->statement("CREATE DATABASE IF NOT EXISTS ".$name);
}

/**
 * @param $name
 * @return bool
 */
function drop_database($name){
    return \Swoft\Db\DB::db('mysql')->statement("DROP DATABASE IF NOT EXISTS ".$name);
}

/**
 * @param int $num
 * @param string $unit
 * @return false|int
 */
function count_date(int $num, $unit = 'day')
{
    return strtotime("+ ".$num.$unit) - time();
}

/**
 * 判断是否需要jwt验证
 * @param string $service
 * @param string $server
 * @param string $action
 * @return bool
 */
function need_valid(string $service, string $server, string $action){
    //这里需要进行查询
    $config = config('service.'.strtolower($service).'_validate_actions', '');
    if(is_json($config)){
        //这里进行解析json
        $validate_actions = json_decode($config, true);
        if(!isset($validate_actions[$server]) || (!$actions = $validate_actions[$server])){
            //代表寻找到了数据
            return false;
        }
    }else{
        $actions = explode(',', $config);
    }
    return in_array('all', $actions) || in_array($action, $actions);
}

/**
 * @param string $str
 * @return bool
 */
function is_json(string $str): bool
{
    json_decode($str);

    return json_last_error() === JSON_ERROR_NONE;
}

/**
 * @param int $identity_id
 * @return mixed|object
 */
function get_user_dao(int $identity_id = 1){
    switch ($identity_id){
        case 999:
            //总后台
            $dao =     BeanFactory::getBean(\App\Rpc\Model\Dao\UserDao::class);
            break;
        case 6:
            //大货主
            $dao =     BeanFactory::getBean(\App\Rpc\Model\Dao\UserBigDao::class);
            break;
        case 5:
            //车队长
            $dao =     BeanFactory::getBean(\App\Rpc\Model\Dao\UserCaptainDao::class);
            break;
        case 4:
            //承运商
            $dao =     BeanFactory::getBean(\App\Rpc\Model\Dao\UserCarrierDao::class);
            break;
        case 3:
            //货主
            $dao =     BeanFactory::getBean(\App\Rpc\Model\Dao\UserConsignerDao::class);
            break;
        case 2:
            //租户
            $dao =     BeanFactory::getBean(\App\Rpc\Model\Dao\UserDao::class);
            break;
        default:
            //这里是司机的信息
            $dao =     BeanFactory::getBean(\App\Rpc\Model\Dao\UserDriverDao::class);
            break;
    }

    return $dao;
}

/**
 * @param $service
 * @param $data
 * @param string $trace_id
 * @return array
 * @throws \App\Exception\RpcConnectException
 * @throws \Swoft\Consul\Exception\ClientException
 * @throws \Swoft\Consul\Exception\ServerException
 */
function request($service, $data, $trace_id = '') :array
{
    $service_ex = [
        'Common.Gateway.Permission.getUserByIdOrPhone',
        'Common.Gateway.Permission.userAccount',
        'Common.Blacklist.Blacklist.isNot',
        'Common.Gateway.Permission.roleList',
        'Common.Gateway.Permission.rolePermissions',
        'Common.Gateway.Permission.userConsignerCreate',
        'Common.Gateway.Permission.userCarrierCreate',
        'Common.Gateway.Permission.userCarrierList',
        'Common.Gateway.Permission.userConsignerList',
        'Common.Gateway.Permission.userConsignerUpdate',
        'Common.Gateway.Permission.userCarrierUpdate',
        'Common.Gateway.Permission.migrate',
        'Common.User.User.migrate',
        'Common.User.User.userInfo',
    ];

    if(env('APP_ENV') == 'local' && !in_array($service, $service_ex)){
        $base_uri = 'https://api-test.99elink.com:30091';
        $uri = '/admin';
        $data['service'] = $service;
        $data['trace_id'] = $trace_id <> ''?$trace_id:uuid();
        vdump($data);
        $result = curl($base_uri, $uri, 'POST', $data, [], true);

        $result_data = json_decode($result, true);
    }else{
        /** @var RpcRequest $RpcClient */
        $RpcClient = BeanFactory::getBean(RpcRequest::class);

        //@end 请求参数
        /** @var RpcResult $reocr */
        $result_data = $result = $RpcClient->getServiceByServiceInfo($service)->setParams($data)->query();
    }

    return $result_data??[];
}

/**
 * 判断是否有数据库
 * @param string $database
 * @return bool
 */
function is_has_database(string $database): bool
{
    $result = \Swoft\Db\DB::db('mysql')->select("SELECT information_schema.SCHEMATA.SCHEMA_NAME FROM information_schema.SCHEMATA where SCHEMA_NAME='".$database."'");
    if(!$result){
        return false;
    }else{
        return true;
    }
}

/**
 * 规范返回数据
 * @param array $list
 * @param int $page
 * @param int $totalNumber
 * @param int $pageSize
 * @return array
 */
function return_list(array $list, int $totalNumber, int $page = 1,  int $pageSize = 10): array
{
    return [
        'list' => $list??[],
        'page' => $page,
        'pageSize' => $pageSize,
        'totalNumber' => $totalNumber,
        'totalPage' => intval(ceil($totalNumber/$pageSize))
    ];
}

/**
 * 把驼峰转化成字带分隔符的小写字符窜
 * @param $string
 * @param string $break
 * @return string
 */
function make_string($string, $break = '-'){
    $arr = str_split($string);
    $new = [];
    foreach ($arr as $key => $value) {
        if($value === strtoupper($value) && $key !== 0){
            $new[] = '-';
        }
        $new[] = $value;
    }
    return strtolower(implode('', $new));
}

/**
 * 开始判断是否可以登录
 * @param int $versionCode
 * @return bool
 */
function min_driver_version(int $versionCode){
    if($versionCode < config('service.min_driver_version', 1)){
        return false;
    }else{
        return true;
    }
}

/**
 * @param string $serviceName
 * @return string
 */
function getSocketDns(string $serviceName){
    if(strtolower($serviceName) == 'statistic'){
        if(env('APP_ENV', 'local') == 'big'){
            $dns = strtolower($serviceName).'-test-svc.datastatistic';
        }else{
            $dns = strtolower($serviceName).'-svc.datastatistic';
        }
    }else{
        if(env('APP_ENV', 'local') == 'v6'){
            $dns = strtolower(make_string($serviceName)).'.'.env('APP_ENV', 'local').config('service.consul_dns', '.micro-service-test.svc.cluster.local');
        }else{
            $dns = strtolower(make_string($serviceName)).'-'.env('APP_ENV', 'local').config('service.consul_dns', '.micro-service-test.svc.cluster.local');
        }
    }

    return $dns;
}
